
Git의 고급 기능부터 효과적인 브랜치 전략까지, 팀 협업을 위한 완벽 가이드
Git은 단순한 버전 관리 도구를 넘어 현대 소프트웨어 개발 팀의 협업을 가능하게 하는 핵심 인프라입니다. 이 글에서는 Git의 고급 기능과 다양한 팀 워크플로우 전략을 살펴보고, 실무에서 바로 적용할 수 있는 팁들을 공유합니다.
깔끔한 커밋 히스토리는 코드 리뷰와 유지보수를 크게 향상시킵니다. git rebase -i를 사용하면 커밋을 재정렬, 병합, 수정할 수 있습니다.
# 최근 5개 커밋을 대화형으로 편집
git rebase -i HEAD~5Rebase 편집 화면에서 사용할 수 있는 명령어:
실전 예시: 여러 개의 "WIP" 커밋을 하나로 합치기
# 작업 중 만든 여러 커밋들
git log --oneline
# a1b2c3d WIP: 버그 수정 시도 3
# d4e5f6g WIP: 버그 수정 시도 2
# h7i8j9k WIP: 버그 수정 시도 1
# l0m1n2o feat: 새로운 기능 추가
# Interactive rebase 시작
git rebase -i HEAD~3
# 편집기에서:
# pick h7i8j9k WIP: 버그 수정 시도 1
# squash d4e5f6g WIP: 버그 수정 시도 2
# squash a1b2c3d WIP: 버그 수정 시도 3
# → "fix: 로그인 버그 수정"으로 하나의 깔끔한 커밋으로 만들기git reflog는 HEAD가 가리켰던 모든 커밋 기록을 저장합니다. 실수로 커밋을 삭제했거나 rebase를 망쳤을 때 생명줄이 됩니다.
# reflog 확인
git reflog
# 출력 예시:
# a1b2c3d HEAD@{0}: rebase -i (finish): returning to refs/heads/feature
# d4e5f6g HEAD@{1}: rebase -i (squash): fix: 로그인 버그 수정
# h7i8j9k HEAD@{2}: commit: WIP: 버그 수정 시도 1
# 특정 시점으로 복구
git reset --hard HEAD@{2}주의사항: reflog는 로컬 저장소에만 존재하며, 보통 90일 후 만료됩니다.
다른 브랜치의 특정 커밋만 가져오고 싶을 때 사용합니다.
# develop 브랜치의 특정 커밋을 현재 브랜치로 가져오기
git cherry-pick a1b2c3d
# 여러 커밋을 한 번에
git cherry-pick a1b2c3d d4e5f6g h7i8j9k
# 커밋을 가져오되 자동 커밋하지 않고 스테이징만
git cherry-pick -n a1b2c3d실무 시나리오: hotfix를 production에 먼저 배포한 후, develop 브랜치에도 적용
# main 브랜치에서 hotfix 작업
git checkout main
git commit -m "hotfix: 크리티컬 보안 패치"
# hotfix 커밋 해시 확인
git log -1 --format="%H" # 예: abc123...
# develop 브랜치로 전환 후 해당 커밋만 가져오기
git checkout develop
git cherry-pick abc123이진 탐색을 사용하여 버그가 발생한 커밋을 효율적으로 찾습니다.
# bisect 시작
git bisect start
# 현재 커밋이 버그 있음을 표시
git bisect bad
# 버그가 없었던 과거 커밋 지정
git bisect good v1.0.0
# Git이 중간 커밋으로 이동 → 테스트 후 good/bad 표시
git bisect good # 또는 git bisect bad
# 반복하면 Git이 문제 커밋을 찾아줌
# 완료 후
git bisect reset자동화: 테스트 스크립트가 있다면 자동으로 실행 가능
git bisect start HEAD v1.0.0
git bisect run npm test하나의 저장소에서 여러 브랜치를 동시에 작업할 수 있습니다.
# 새로운 worktree 생성
git worktree add ../project-feature-a feature-a
git worktree add ../project-hotfix hotfix/critical-bug
# worktree 목록 확인
git worktree list
# worktree 제거
git worktree remove ../project-feature-a사용 사례:
가장 널리 알려진 브랜치 전략으로, 명확한 역할 분담과 릴리스 관리가 특징입니다.
브랜치 구조:
main (production)
└─ hotfix/* # 긴급 수정
develop # 개발 통합
├─ feature/* # 새 기능
├─ release/* # 릴리스 준비
└─ bugfix/* # 버그 수정
워크플로우:
# 1. 새 기능 개발 시작
git checkout develop
git checkout -b feature/user-authentication
# 2. 작업 후 develop에 병합
git checkout develop
git merge --no-ff feature/user-authentication
git branch -d feature/user-authentication
# 3. 릴리스 준비
git checkout -b release/1.2.0 develop
# 버전 번호 업데이트, 마이너 버그 수정
# 4. 릴리스 완료
git checkout main
git merge --no-ff release/1.2.0
git tag -a v1.2.0 -m "Version 1.2.0"
git checkout develop
git merge --no-ff release/1.2.0
git branch -d release/1.2.0
# 5. 긴급 수정 (Hotfix)
git checkout -b hotfix/1.2.1 main
# 수정 작업
git checkout main
git merge --no-ff hotfix/1.2.1
git tag -a v1.2.1
git checkout develop
git merge --no-ff hotfix/1.2.1
git branch -d hotfix/1.2.1장점:
단점:
단순함을 추구하는 전략으로, 지속적 배포 환경에 최적화되어 있습니다.
브랜치 구조:
main (항상 배포 가능한 상태)
├─ feature/login-page
├─ fix/mobile-layout
└─ hotfix/security-patch
워크플로우:
# 1. main에서 브랜치 생성
git checkout main
git pull origin main
git checkout -b feature/social-login
# 2. 작업하고 정기적으로 푸시
git add .
git commit -m "feat: Google OAuth 구현"
git push origin feature/social-login
# 3. Pull Request 생성 (GitHub UI)
# - 코드 리뷰
# - CI/CD 자동 테스트
# - 승인 후 병합
# 4. 병합 후 배포
git checkout main
git pull origin main
# main 브랜치가 자동으로 배포됨장점:
단점:
모범 사례:
# 브랜치 이름 규칙
feature/기능명 # 예: feature/payment-integration
fix/버그명 # 예: fix/cart-calculation-error
hotfix/긴급수정 # 예: hotfix/xss-vulnerability
docs/문서작업 # 예: docs/api-documentation짧은 생명 주기의 브랜치로 메인 브랜치에 자주 병합하는 전략입니다.
핵심 원칙:
main (trunk)에 직접 또는 짧은 수명의 브랜치에서 작업워크플로우:
# 1. 작은 단위로 자주 커밋
git checkout main
git pull origin main
git checkout -b short-lived-branch
# 2-3시간 작업 후 병합
git add .
git commit -m "feat: 결제 모듈 일부 구현 (Feature Flag 적용)"
git push origin short-lived-branch
# 3. 빠르게 리뷰하고 병합
git checkout main
git merge short-lived-branch
git push origin main
git branch -d short-lived-branch
# 4. Feature Flag로 기능 제어
if (featureFlags.newPaymentSystem) {
// 새 결제 시스템
} else {
// 기존 결제 시스템
}Feature Flag 예시:
// config/features.ts
export const featureFlags = {
newPaymentSystem: process.env.ENABLE_NEW_PAYMENT === 'true',
betaUI: process.env.ENABLE_BETA_UI === 'true',
};
// 사용
import { featureFlags } from '@/config/features';
function PaymentPage() {
if (featureFlags.newPaymentSystem) {
return <NewPaymentSystem />;
}
return <LegacyPaymentSystem />;
}장점:
단점:
Merge:
git checkout feature
git merge main
# 장점: 히스토리 보존, 안전함
# 단점: 병합 커밋으로 히스토리 복잡해짐Rebase:
git checkout feature
git rebase main
# 장점: 깔끔한 선형 히스토리
# 단점: 히스토리 재작성 (푸시된 브랜치 주의)황금률: 공유된 브랜치는 rebase 금지, 로컬 브랜치만 rebase
# 1. 충돌 발생
git merge feature-branch
# Auto-merging src/app.ts
# CONFLICT (content): Merge conflict in src/app.ts
# 2. 충돌 파일 확인
git status
# 3. 파일 편집
# <<<<<<< HEAD
# 현재 브랜치 코드
# =======
# 병합하려는 브랜치 코드
# >>>>>>> feature-branch
# 4. 충돌 해결 후
git add src/app.ts
git commit -m "Merge feature-branch, resolve conflicts"
# 병합 취소하려면
git merge --abort도구 활용:
# VS Code, IntelliJ 등 IDE의 내장 도구 사용
# 또는 전용 merge tool
git mergetool --tool=vimdiff# 매일 아침 main 브랜치 변경사항 가져오기
git checkout feature
git fetch origin
git rebase origin/main# 좋은 예: 각 기능별로 브랜치 분리
feature/user-auth → src/auth/*
feature/payment → src/payment/*
# 나쁜 예: 한 브랜치에서 모든 작업
feature/mega-update → 모든 파일 수정# .prettierrc 또는 .eslintrc로 스타일 통일
npm run format
git add .
git commit -m "style: 코드 포맷 적용"Conventional Commits 표준:
# 형식
<type>(<scope>): <subject>
<body>
<footer>
# 예시
feat(auth): JWT 토큰 갱신 로직 추가
기존 토큰이 만료되기 5분 전에 자동으로
새로운 토큰을 요청하도록 구현
Closes #123Type 종류:
feat: 새 기능fix: 버그 수정docs: 문서 변경style: 코드 포맷 (동작 변경 없음)refactor: 리팩토링test: 테스트 추가/수정chore: 빌드, 설정 변경GitHub/GitLab 설정:
# .github/branch-protection.yml (예시)
main:
required_reviews: 2
require_codeowner_review: true
require_status_checks:
- ci/test
- ci/lint
enforce_admins: false
allow_force_pushes: false
allow_deletions: false## 코드 리뷰 체크리스트
### 기능성
- [ ] 요구사항 충족
- [ ] 엣지 케이스 처리
- [ ] 에러 핸들링
### 코드 품질
- [ ] 읽기 쉬운 코드
- [ ] 적절한 변수/함수명
- [ ] 중복 코드 없음
- [ ] 테스트 코드 포함
### 보안
- [ ] 입력 검증
- [ ] SQL Injection 방어
- [ ] XSS 방어
- [ ] 민감 정보 노출 없음
### 성능
- [ ] 불필요한 연산 없음
- [ ] 적절한 자료구조 사용
- [ ] N+1 쿼리 없음# ~/.gitconfig
[alias]
st = status -sb
co = checkout
br = branch
cm = commit -m
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
undo = reset --soft HEAD^
amend = commit --amend --no-edit
unstage = reset HEAD --
# 현재 브랜치를 origin에 푸시
publish = "!git push -u origin $(git branch --show-current)"
# 병합된 브랜치 일괄 삭제
cleanup = "!git branch --merged | grep -v '\\*\\|main\\|develop' | xargs -n 1 git branch -d"# ~/.gitmessage
# <type>(<scope>): <subject>
#
# <body>
#
# <footer>
#
# Type: feat, fix, docs, style, refactor, test, chore
# Scope: 변경 범위 (auth, api, ui 등)
# Subject: 50자 이내 요약
# Body: 상세 설명 (선택)
# Footer: 이슈 번호 (Closes #123)
# Git에 템플릿 등록
git config --global commit.template ~/.gitmessage# .git/hooks/pre-commit
#!/bin/bash
echo "Running pre-commit checks..."
# Lint 검사
npm run lint
if [ $? -ne 0 ]; then
echo "Lint failed. Commit aborted."
exit 1
fi
# 테스트 실행
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Commit aborted."
exit 1
fi
echo "All checks passed!"Husky로 자동화:
# package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"]
}
}Git은 단순한 명령어 도구가 아니라 팀의 협업 문화를 반영하는 시스템입니다. 프로젝트 규모와 팀 특성에 맞는 브랜치 전략을 선택하고, 명확한 컨벤션과 자동화된 검증 프로세스를 구축하는 것이 성공적인 협업의 핵심입니다.
추천 접근법:
모든 전략에는 트레이드오프가 있습니다. 팀과 함께 실험하고, 회고를 통해 지속적으로 개선해나가는 것이 가장 중요합니다.
참고 자료: